`include "defines.v"

module SimTop(
    input  wire         clock,
    input  wire         reset,

    input  wire [63: 0] io_logCtrl_log_begin,
    input  wire [63: 0] io_logCtrl_log_end,
    input  wire [63: 0] io_logCtrl_log_level,
    input  wire         io_perfInfo_clean,
    input  wire         io_perfInfo_dump,

    output wire         io_uart_out_valid,
    output wire [ 7: 0] io_uart_out_ch,
    output wire         io_uart_in_valid,
    input  wire [ 7: 0] io_uart_in_ch
);

//CPU TOPMAIN
wire         inst_ena;
wire [31: 0] inst_mem_data;
wire [63: 0] inst_mem_addr;
wire [`xlen] ram_rd_data;
wire [63: 0] ram_addr;
wire [`xlen] ram_wr_data;
wire         ram_wr_en;
wire         ram_rd_en;
wire [`BUSLEN] ram_wmask;
//for sim
wire rd_w_ena;
wire [4:0] rd_w_addr;
wire [`xlen] rd_data;
wire [63: 0] pc;
wire [`INSTLEN] inst;
wire load_use_stall;
wire flush;

RVCPU RVCPU (
    .clk(clock),
    .rst(reset),
    .load_use_stall(load_use_stall),
    .flush(flush),

    .inst_mem_data(inst_mem_data),
    .inst_ena(inst_ena),
    .inst_mem_addr(inst_mem_addr),

    .ram_rd_data(ram_rd_data),
    .ram_addr(ram_addr),

    .ram_wr_data(ram_wr_data),
    .ram_rd_en(ram_rd_en),
    .ram_wr_en(ram_wr_en),
    .ram_wmask(ram_wmask),

    //for sim
    .gpr(regs_diff),
    .RegWr(rd_w_ena),
    .rd_addr(rd_w_addr),
    .data_to_reg(rd_data),
    .pc_addr(pc),
    .inst(inst)
);


//RAM
RAM_1W2R RAM(
    .clk(clock),
    
    .inst_addr(inst_mem_addr),
    .inst_ena(inst_ena),
    .inst(inst_mem_data),

    .ram_wr_en(ram_wr_en),
    .ram_rd_en(ram_rd_en),
    .ram_wmask(ram_wmask),    
    .ram_addr(ram_addr),
    .ram_wr_data(ram_wr_data),
    .ram_rd_data(ram_rd_data)
);


// Difftest
reg cmt_wen;
reg [7:0] cmt_wdest;
reg [`xlen] cmt_wdata;
reg [`xlen] cmt_pc_delay1;
reg [`xlen] cmt_pc_delay2;
reg [`xlen] cmt_pc_delay3;
reg [`xlen] cmt_pc;
reg [31:0] cmt_inst_delay1;
reg [31:0] cmt_inst_delay2;
reg [31:0] cmt_inst_delay3;
reg [31:0] cmt_inst;
reg cmt_valid;
wire trap;
//reg [7:0] trap_code;
reg [63:0] cycleCnt;
reg [63:0] instrCnt;
reg [`xlen] regs_diff [31: 0];
wire        valid;

assign valid = ~skip[3] ;
assign trap = (cmt_inst[6:0] == 7'h6b) ;

always@(posedge clock) begin
  if (cmt_inst[6:0] == 7'h7b) begin
    $write("%c",regs_diff[10]);
  end
end

always @(posedge clock) begin
  if (reset) begin
    {cmt_wen, cmt_wdest, cmt_wdata, cmt_pc_delay1 , cmt_pc_delay2 , cmt_pc_delay3 , cmt_pc, cmt_inst, cmt_inst_delay1 , cmt_inst_delay2 , cmt_inst_delay3 , cmt_valid, cycleCnt, instrCnt} <= 0;
  end
  else if (~trap) begin
    cmt_wen <= rd_w_ena;
    cmt_wdest <= {3'd0, rd_w_addr};
    cmt_wdata <= (|rd_w_addr) ? rd_data : 64'b0 ;

    cmt_pc_delay1 <= pc;
    cmt_pc_delay2 <= cmt_pc_delay1;
    cmt_pc_delay3 <= cmt_pc_delay2;
    
    if(valid) begin
      cmt_pc <= cmt_pc_delay3;
    end
    else begin
      cmt_pc <= cmt_pc;
    end

    cmt_inst_delay1 <= inst;
    cmt_inst_delay2 <= cmt_inst_delay1;
    cmt_inst_delay3 <= cmt_inst_delay2;

     if(valid) begin
      cmt_inst <= cmt_inst_delay3;
    end
    else begin
      cmt_inst <= cmt_inst;
    end

    cmt_valid <= valid;

   // trap_code <= 8'b0;
    cycleCnt <= cycleCnt + 1'b1;
    instrCnt <= instrCnt + valid;
  end
end

//skip nop
reg [3:0] skip;
always @(posedge clock) begin
  if(reset) skip <= 4'b0;
  else begin
    skip[3] <= skip[2];
    skip[2] <= flush | skip[1];
    skip[1] <= flush | skip[0] | load_use_stall;
    skip[0] <= flush ;
  end
end


DifftestInstrCommit DifftestInstrCommit(
  .clock              (clock),
  .coreid             (0),
  .index              (0),
  .valid              (cmt_valid),
  .pc                 (cmt_pc),
  .instr              (cmt_inst),
  .skip               (cmt_inst[6:0] == 7'h7b | (cmt_inst[6:0] == 7'h73 & cmt_inst[31:20] ==12'hB00) ),
  .isRVC              (0),
  .scFailed           (0),
  .wen                (cmt_wen),
  .wdest              (cmt_wdest),
  .wdata              (cmt_wdata)
);

DifftestArchIntRegState DifftestArchIntRegState (
  .clock              (clock),
  .coreid             (0),
  .gpr_0              (regs_diff[0]),
  .gpr_1              (regs_diff[1]),
  .gpr_2              (regs_diff[2]),
  .gpr_3              (regs_diff[3]),
  .gpr_4              (regs_diff[4]),
  .gpr_5              (regs_diff[5]),
  .gpr_6              (regs_diff[6]),
  .gpr_7              (regs_diff[7]),
  .gpr_8              (regs_diff[8]),
  .gpr_9              (regs_diff[9]),
  .gpr_10             (regs_diff[10]),
  .gpr_11             (regs_diff[11]),
  .gpr_12             (regs_diff[12]),
  .gpr_13             (regs_diff[13]),
  .gpr_14             (regs_diff[14]),
  .gpr_15             (regs_diff[15]),
  .gpr_16             (regs_diff[16]),
  .gpr_17             (regs_diff[17]),
  .gpr_18             (regs_diff[18]),
  .gpr_19             (regs_diff[19]),
  .gpr_20             (regs_diff[20]),
  .gpr_21             (regs_diff[21]),
  .gpr_22             (regs_diff[22]),
  .gpr_23             (regs_diff[23]),
  .gpr_24             (regs_diff[24]),
  .gpr_25             (regs_diff[25]),
  .gpr_26             (regs_diff[26]),
  .gpr_27             (regs_diff[27]),
  .gpr_28             (regs_diff[28]),
  .gpr_29             (regs_diff[29]),
  .gpr_30             (regs_diff[30]),
  .gpr_31             (regs_diff[31])
);

DifftestTrapEvent DifftestTrapEvent(
  .clock              (clock),
  .coreid             (0),
  .valid              (trap),
  .code               ( |regs_diff[10] ),
  //.code               (trap_code),
  .pc                 (cmt_pc),
  .cycleCnt           (cycleCnt),
  .instrCnt           (instrCnt)
);

//don't care
DifftestCSRState DifftestCSRState(
  .clock              (clock),
  .coreid             (0),
  .priviledgeMode     (0),
  .mstatus            (0),
  .sstatus            (0),
  .mepc               (0),
  .sepc               (0),
  .mtval              (0),
  .stval              (0),
  .mtvec              (0),
  .stvec              (0),
  .mcause             (0),
  .scause             (0),
  .satp               (0),
  .mip                (0),
  .mie                (0),
  .mscratch           (0),
  .sscratch           (0),
  .mideleg            (0),
  .medeleg            (0)
);

DifftestArchFpRegState DifftestArchFpRegState(
  .clock              (clock),
  .coreid             (0),
  .fpr_0              (0),
  .fpr_1              (0),
  .fpr_2              (0),
  .fpr_3              (0),
  .fpr_4              (0),
  .fpr_5              (0),
  .fpr_6              (0),
  .fpr_7              (0),
  .fpr_8              (0),
  .fpr_9              (0),
  .fpr_10             (0),
  .fpr_11             (0),
  .fpr_12             (0),
  .fpr_13             (0),
  .fpr_14             (0),
  .fpr_15             (0),
  .fpr_16             (0),
  .fpr_17             (0),
  .fpr_18             (0),
  .fpr_19             (0),
  .fpr_20             (0),
  .fpr_21             (0),
  .fpr_22             (0),
  .fpr_23             (0),
  .fpr_24             (0),
  .fpr_25             (0),
  .fpr_26             (0),
  .fpr_27             (0),
  .fpr_28             (0),
  .fpr_29             (0),
  .fpr_30             (0),
  .fpr_31             (0)
);

endmodule
